#pragma once

#include "SbotPlugin.hpp"
#include <QObject>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include <QQuickWindow>
#include <mutex>

#define IDE_CONFIG_FILE_PATH       "./sbotIde.cfg"
#define IDE_CACHE_PATH             "./.cache"
// #define PLUGIN_PATH                "D:/WorkSpace/SBOT/SbotPlugins/BuildPlugins/"
#define PLUGIN_PATH                "./Plugins/"

#define MAIN_WINDOWS_QML_FILE_PATH "qrc:Qml/MainWindow.qml"  // Main winodws view file path.
#define SBOTIDE                    SbotIde::getInstance()

#define SBT_MSG(msg, title)        SBOTIDE.showMessage(title, msg);
#define SBT_MSG_E(msg)             SBOTIDE.showMessage("ERROE", msg);
#define SBT_MSG_W(msg)             SBOTIDE.showMessage("WARNING", msg);
#define SBT_MSG_I(msg)             SBOTIDE.showMessage("INFO", msg);
#define SBT_MSG_D(msg)             SBOTIDE.showMessage("DEBUG", msg);

class SbotIde : public QObject {
    Q_OBJECT

public:
    static SbotIde& getInstance();
    explicit SbotIde(QObject* parent = nullptr);

    /**
     * @brief Run the IDE.
     *
     * @param argc The number of arguments.
     * @param argv The arguments.
     */
    void run(int argc, char* argv[]);

    /**
     * @brief Create a Quick Item object
     *
     * @param filePath the qml file path.
     * @return QQuickItem* the Quick Item object.
     */
    QQuickItem* createQuickItem(const QString& filePath);

    /**
     * @brief Show a message dialog.
     *
     * @param title Message title.
     * @param message Message content.
     */
    void showMessage(const QString& title = "Message", const QString& message = "");

    /**
     * @brief Detect plugins.
     *
     * @param path File path to search for plugins.
     */
    void detectPlugins(const QString& path);

    /**
     * @brief Load a plugin.
     *
     * @param filePath Plugin file path.
     */
    void loadPlugin(const QString& filePath);

    /**
     * @brief Reload a plugin.
     *
     * @param index Plugin index at "m_plugins".
     */
    Q_INVOKABLE void reloadPlugin(int index);

    /**
     * @brief Remove a plugin.
     *
     * @param index Plugin index at "m_plugins".
     */
    Q_INVOKABLE void removePlugin(int index);

    /**
     * @brief Open a plugin.
     *
     * @param index Plugin index at "m_plugins".
     */
    Q_INVOKABLE void openPlugin(int index);

    /**
     * @brief Close a plugin.
     *
     * @param index Plugin index at "m_plugins".
     */
    Q_INVOKABLE void closePlugin(int index);

    /**
     * @brief Set the Theme Manager object
     *
     * @param item The theme Manager object.
     */
    Q_INVOKABLE void setThemeManager(QObject* item);

    /**
     * @brief Load IDE config.
     *
     */
    void loadIdeConfig();

    /**
     * @brief Save IDE config.
     *
     * @return Q_INVOKABLE
     */
    Q_INVOKABLE void saveIdeConfig();

public slots:
    void aboutToQuit();

private:
    QQmlApplicationEngine* m_engine          = nullptr;
    QObject*               m_themeManager    = nullptr;
    QQuickItem*            m_mainContentItem = nullptr;
    QList< SbotPlugin* >   m_plugins;

    static SbotIde*       instance;
    static std::once_flag initInstanceFlag;
    static void           initInstance();

    /**
     * @brief Parse a SbotPlugin.
     *
     * @param filePath Plugin file path.
     * @return SbotPlugin* Plgugin object.
     */
    SbotPlugin* parseSbotPlugin(const QString& filePath);

    /**
     * @brief Refresh the plugins list view.
     *
     */
    void refreshPluginsListView();
};